// show-ahead SRL-based fifo

`timescale 1ns/1ps

module sr_fifo
#(parameter
    DATA_BITS  = 8,
    DEPTH_BITS = 4
)
(
    input  wire                 I_sclk,
    input  wire                 I_rst_n,
    output wire                 O_empty,
    output wire                 O_full,
    input  wire                 I_rdreq,
    input  wire                 I_wrreq,
    output wire [DATA_BITS-1:0] O_q,
    input  wire [DATA_BITS-1:0] I_data
);
//------------------------Parameter----------------------
localparam
    DEPTH = 1 << DEPTH_BITS;
//------------------------Local signal-------------------
reg                   empty;
reg                   full;
reg  [DEPTH_BITS-1:0] pout;
reg  [DATA_BITS-1:0]  mem[0:DEPTH-1];
//------------------------Body---------------------------
assign O_empty = empty;
assign O_full  = full;
assign O_q     = mem[pout];

// empty
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        empty <= 1'b1;
    else if (I_wrreq)
        empty <= 1'b0;
    else if (I_rdreq && pout == 1'b0)
        empty <= 1'b1;
end

// full
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        full <= 1'b0;
    else if (I_rdreq)
        full <= 1'b0;
    else if (I_wrreq && pout == { {(DEPTH_BITS-1){1'b1}}, 1'b0 })
        full <= 1'b1;
end

// pout
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        pout <= 1'b0;
    else if (I_wrreq & ~I_rdreq & ~empty)
        pout <= pout + 1'b1;
    else if (~I_wrreq && I_rdreq && pout != 1'b0)
        pout <= pout - 1'b1;
end

integer i;
always @(posedge I_sclk) begin
    if (I_wrreq) begin
        for (i = 0; i < DEPTH - 1; i = i + 1) begin
            mem[i+1] <= mem[i];
        end
        mem[0] <= I_data;
    end
end

endmodule

// vim:ts=4 sw=4 et fdm=marker:

